package com.wei.service.impl;

import com.wei.common.SysConfigCodeDefinition;
import com.wei.dao.Page;
import com.wei.dao.read.PatientReadMapper;
import com.wei.dao.read.PrescriptionReadMapper;
import com.wei.dao.read.SchedulingDetailReadMapper;
import com.wei.dao.read.SysConfigReadMapper;
import com.wei.dao.write.PrescriptionOptMapper;
import com.wei.dao.write.PtVisitOptMapper;
import com.wei.dao.write.SchedulingDetailOptMapper;
import com.wei.dao.write.SysConfigOptMapper;
import com.wei.entity.*;
import com.wei.entity.dto.AppointRecordDto;
import com.wei.entity.vo.AppointmentVo;
import com.wei.entity.vo.SchedulingDetailVo;
import com.wei.service.ISchedulingDetailService;
import com.wei.service.mapstruct.AppointmentMapperImpl;
import com.wei.utils.ApplicationConstants;
import com.wei.utils.CollectionUtils;
import com.wei.utils.ExceptionUtils;
import com.wei.utils.Stringutils;
import com.wei.utils.date.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

@Service
@Transactional
public class SchedulingDetailServiceImpl implements ISchedulingDetailService {
    @Autowired
    private SchedulingDetailOptMapper schedulingDetailOptMapper;
    @Autowired
    private SchedulingDetailReadMapper schedulingDetailReadMapper;
    @Autowired
    private PatientReadMapper patientReadMapper;
    @Autowired
    private PrescriptionReadMapper prescriptionReadMapper;
    @Autowired
    private PtVisitOptMapper ptVisitOptMapper;
    @Autowired
    private SysConfigReadMapper sysConfigReadMapper;
    @Autowired
    private SysConfigOptMapper sysConfigOptMapper;
    @Autowired
    private PrescriptionOptMapper prescriptionOptMapper;


    public boolean insert(SchedulingDetail schedulingDetail) {
        return schedulingDetailOptMapper.insert(schedulingDetail) > 0;
    }

    public boolean update(SchedulingDetail schedulingDetail) {
        return schedulingDetailOptMapper.update(schedulingDetail) > 0;
    }

    public boolean delete(Integer id) {
        return schedulingDetailOptMapper.delete(id) > 0;
    }

    public boolean batchSava(List<SchedulingDetail> schedulingDetailList) {
        return schedulingDetailOptMapper.batchSava(schedulingDetailList) > 0;
    }

    public SchedulingDetail getById(Integer id) {
        return schedulingDetailReadMapper.getById(id);
    }

    public Integer totalCount() {
        return schedulingDetailReadMapper.totalCount();
    }

    public List<SchedulingDetail> getAll(Page<SchedulingDetail> page) {
        return schedulingDetailReadMapper.getAll(page);
    }

    public List<SchedulingDetail> getRegistrationSource(Map<String, String> maps) {
        return schedulingDetailReadMapper.getRegistrationSource(maps);
    }

    //预约
    public boolean appointment(Map<String, String> maps) {
        String sourceId = maps.get("sourceId");
        String ioNo = maps.get("ioNo");
        if (Stringutils.isEmpty(sourceId)) {
            throw ExceptionUtils.mpeValidator("%s", "号源id不能为空!");
        }
        if (Stringutils.isEmpty(ioNo)) {
            throw ExceptionUtils.mpeValidator("%s", "就诊号不能为空!");
        }
        Patient patient = patientReadMapper.getByIoNo(ioNo);
        SchedulingDetailVo detailVo = schedulingDetailReadMapper.getSchedulingDetailVoBySourceId(sourceId);
        checkFor(patient, detailVo);

        if (ApplicationConstants.Y.equals(detailVo.getRegState())) {
            throw ExceptionUtils.mpeValidator("%s", "该号源已被占用,请选择其他时间段!");
        }
        if (DateUtils.format(new Date(), "yyyy-MM-dd").equals(DateUtils.format(detailVo.getScheDate(), "yyyy-MM-dd"))) {
            throw ExceptionUtils.mpeValidator("%s", "当天号源无法预约!");
        }

        Integer count = schedulingDetailReadMapper.getAppointmentCheck(detailVo.getRegScheId().toString(),
                patient.getPtId().toString(), detailVo.getRegApe());
        if (count > 0) {
            throw ExceptionUtils.mpeValidator("%s", "当天科室已有预约,无法重复预约!");
        }


        Appointment appointment = new Appointment();
        appointment.setAppointScheId(detailVo.getRegScheId());
        appointment.setAppointName(patient.getPtName());
        appointment.setAppoinitPtId(patient.getPtId());
        appointment.setAppointIoNo(patient.getPtIoNo());
        appointment.setAppointNo(ApplicationConstants.EMPTY);
        appointment.setAppointPhone(patient.getPtPhone());
        appointment.setAppointDrCode(detailVo.getDrCode());
        appointment.setAppointDeptCode(detailVo.getDeptCode());
        appointment.setAppointApn(detailVo.getRegApe());
        appointment.setAppointDate(detailVo.getScheDate());
        appointment.setAppointTime(detailVo.getRegTime());
        appointment.setAppointState("1");
        appointment.setAppointUseType("01");
        appointment.setAppointUseName("微信小程序");
        appointment.setAppointCreateDate(new Date());
        appointment.setAppointOptCode("001");
        appointment.setSchedulingDetailId(detailVo.getRegId());
        count = schedulingDetailOptMapper.insertAppointment(appointment);
        if (count <= 0) {
            throw ExceptionUtils.mpe("%s", "预约表保存失败!");
        }
        count = schedulingDetailOptMapper.updateSchedulingDetailStatus(detailVo.getRegId().toString());
        if (count <= 0) {
            throw ExceptionUtils.mpe("%s", "号源状态已更新!");
        }
        if ("1".equals(detailVo.getRegApe())) {
            count = schedulingDetailOptMapper.updateSchedulingAmNumber(detailVo.getRegScheId().toString());
        } else if ("2".equals(detailVo.getRegApe())) {
            count = schedulingDetailOptMapper.updateSchedulingPmNumber(detailVo.getRegScheId().toString());
        } else if ("3".equals(detailVo.getRegApe())) {
            count = schedulingDetailOptMapper.updateSchedulingEveNumber(detailVo.getRegScheId().toString());
        }
        if (count <= 0) {
            throw ExceptionUtils.mpe("%s", "号源数量更新失败!");
        }
        return true;
    }

    //取消预约
    public boolean cancelAppointment(Map<String, String> maps) {
        String appointId = maps.get("appointId");
        if (Stringutils.isEmpty(appointId)) {
            throw ExceptionUtils.mpeValidator("%s", "预约id不能为空!");
        }
        Integer count = schedulingDetailOptMapper.cancelAppointment(appointId);
        return count > 0;
    }

    //挂号
    public boolean register(Map<String, String> maps) {
        String sourceId = maps.get("sourceId");
        String ioNo = maps.get("ioNo");
        String appointId = maps.get("appointId");//如果传了appointId表示预约挂号
        String child = maps.get("child");
        //读取配置
        String target = maps.get("target");//100014
        if (Stringutils.isEmpty(sourceId)) {
            throw ExceptionUtils.mpeValidator("%s", "号源id不能为空!");
        }
        if (Stringutils.isEmpty(ioNo)) {
            throw ExceptionUtils.mpeValidator("%s", "就诊号不能为空!");
        }
        Patient patient = patientReadMapper.getByIoNo(ioNo);
        SchedulingDetailVo detailVo = schedulingDetailReadMapper.getSchedulingDetailVoBySourceId(sourceId);
        checkFor(patient, detailVo);

        if (Stringutils.isEmpty(appointId) && ApplicationConstants.Y.equals(detailVo.getRegState())) {
            throw ExceptionUtils.mpeValidator("%s", "该号源已被占用,请选择其他时间段!");
        }
        if (!DateUtils.format(detailVo.getScheDate(),DateUtils.DATE_PATTERN).equals(DateUtils.format(new Date(),DateUtils.DATE_PATTERN))) {
            throw ExceptionUtils.mpeValidator("%s", "非当天号源无法挂号!");
        }

        Integer count = schedulingDetailReadMapper.getRegisterCheck(detailVo.getRegScheId().toString(),
                patient.getPtId().toString(), detailVo.getRegApe());
        if (count > 0) {
            throw ExceptionUtils.mpeValidator("%s", "当天科室已有挂号,无法重复挂号!");
        }
//保存就诊表
        Integer series = patientReadMapper.getMaxVisitSeries(patient.getPtId()) + 1;
        PtVisit visit = new PtVisit();
        visit.setVisitSeries(series);
        visit.setPtId(patient.getPtId());
        visit.setVisitType("0");
        visit.setPtName(patient.getPtName());
        visit.setVisitDeptCode(detailVo.getDeptCode());
        visit.setVisitDeptName(detailVo.getDeptName());
        visit.setVisitTime(new Date());
        visit.setVisitStatus("1");
        visit.setDrCode(detailVo.getDrCode());
        visit.setOptCode("001");
        visit.setMedicalStatus("0");

        Integer visitId = ptVisitOptMapper.insert(visit);
        List<DicChargeFee> dicChargeFeeList = prescriptionReadMapper.getDicChargeFeeListByRegCode(detailVo.getScheRegTypeCode());
        //组织费用
        BigDecimal total = new BigDecimal(0l);
        List<Charge> chargeList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(dicChargeFeeList)) {

            for (int index = 0; index < dicChargeFeeList.size(); index++) {
                Charge charge = new Charge();
                charge.setChargeType("0");
                charge.setChargeType("0");
                charge.setVisitId(visitId);
                charge.setVisitSeries(series);
                charge.setPtId(patient.getPtId());
                charge.setPrescriptionId(0);
                charge.setType(dicChargeFeeList.get(index).getFeeTypeCode());
                charge.setChargeCode(dicChargeFeeList.get(index).getFeeCode());
                charge.setChargeName(dicChargeFeeList.get(index).getFeeName());
                charge.setFeeSpecification(dicChargeFeeList.get(index).getFeeSpecification());
                charge.setFeeUnitCode(dicChargeFeeList.get(index).getFeeUnitCode());
                charge.setFeeUnitName(dicChargeFeeList.get(index).getFeeUnitName());
                charge.setFeeDoseUnit(dicChargeFeeList.get(index).getFeeUnitCode());
                charge.setFeePackunit(dicChargeFeeList.get(index).getFeeUnitCode());
                if (child == ApplicationConstants.Y) {
                    charge.setFee(dicChargeFeeList.get(index).getFeeChildPrice());
                } else {
                    charge.setFee(dicChargeFeeList.get(index).getFeePrice());
                }
                charge.setChargeAmount(new BigDecimal(1));
                charge.setFeeSum(charge.getFee().multiply(charge.getChargeAmount()).setScale(2, BigDecimal.ROUND_HALF_UP));
                charge.setFeeStatus("1");
                charge.setExecDeptCode(detailVo.getDeptCode());
                charge.setApplyDeptCode(detailVo.getDeptCode());
                charge.setChargeDate(new Date());
                charge.setApplyTime(new Date());
                charge.setChargeTime(new Date());
                chargeList.add(charge);
            }
        }
        visit.setRegisterFee(total);
        //组织main
//获取虚拟发票号
        SysConfig sysConfig = sysConfigReadMapper.getBySysCode(SysConfigCodeDefinition.CODE_100012);
        if (sysConfigOptMapper.increment(sysConfig) <= 0) {
            throw ExceptionUtils.mpe("%s", "更新虚拟发票号失败");
        }

        String chargeDeptCode = ApplicationConstants.EMPTY;
        String empCode = ApplicationConstants.EMPTY;
        SysConfig chargeDeptSysCfg = sysConfigReadMapper.getBySysCode(target);
        if (chargeDeptSysCfg != null) {
            String sysStr = chargeDeptSysCfg.getSysStr();
            String[] split = Stringutils.split(sysStr, ApplicationConstants.COMMA);
            if (split != null && split.length > 0) {
                chargeDeptCode = split[0];
                if (split.length > 1) {
                    empCode = split[1];
                }
            }
        }
        Main main = new Main();
        main.setChargeType(visit.getVisitType());
        main.setVisitId(visitId);
        main.setVisitSeries(visit.getVisitSeries());
        main.setPtId(visit.getPtId());
        main.setMainInvoice(sysConfig.getSysNumber().toString());
        main.setMainFee(total);
        main.setMainStatus("1");
        main.setMainChargeDeptCode(chargeDeptCode);
        main.setMainEmpCode(empCode);
        main.setMainOccType("R");
        main.setMainTime(new Date());
        main.setMainSelfpay(total);
        main.setMainAccount(new BigDecimal(0));
        main.setMainAccumulate(new BigDecimal(0));
        main.setMainCivil(new BigDecimal(0));
        main.setMainSupp(new BigDecimal(0));
        main.setMainEnterpriseSupp(new BigDecimal(0));
        //保存main
        Integer mainId = prescriptionOptMapper.savaMain(main);

        chargeList.forEach(m -> {
            m.setMainId(mainId);

            Integer in = prescriptionOptMapper.savaCharge(m);
            if (in <= 0) {
                throw ExceptionUtils.mpe("%s", "费用信息记录生成失败!");
            }
        });
        //组织register
        Register register = new Register();
        register.setMainId(mainId);
        register.setVisitId(visitId);
        register.setVisitSeries(series);
        register.setPtId(patient.getPtId());
        register.setPtName(patient.getPtName());
        register.setRegDrCode(detailVo.getDrCode());
        register.setRegDeptCode(detailVo.getDeptCode());
        register.setScheId(detailVo.getRegScheId());
        register.setApn(detailVo.getRegApe());
        register.setTime(detailVo.getRegTime());
        register.setRegTime(new Date());
        register.setStatus("1");
        register.setRegOperCode(empCode);
        register.setFee(total);
        register.setSchedulingDetailId(detailVo.getRegId());
        count = prescriptionOptMapper.savaRegister(register);
        if (count <= 0) {
            throw ExceptionUtils.mpe("%s", "挂号记录生成失败!");
        }

        if (Stringutils.isEmpty(appointId)) {//更新号源
            count = schedulingDetailOptMapper.updateSchedulingDetailStatus(detailVo.getRegId().toString());
            if (count <= 0) {
                throw ExceptionUtils.mpe("%s", "号源状态已更新!");
            }
        } else {//更新预约表
            count = schedulingDetailOptMapper.updateAppointmentStatus(appointId);
            if (count <= 0) {
                throw ExceptionUtils.mpe("%s", "预约状态已更新!");
            }
        }
//更新排班
        if ("1".equals(detailVo.getRegApe())) {
            count = schedulingDetailOptMapper.updateSchedulingAmNumber(detailVo.getRegScheId().toString());
        } else if ("2".equals(detailVo.getRegApe())) {
            count = schedulingDetailOptMapper.updateSchedulingPmNumber(detailVo.getRegScheId().toString());
        } else if ("3".equals(detailVo.getRegApe())) {
            count = schedulingDetailOptMapper.updateSchedulingEveNumber(detailVo.getRegScheId().toString());
        }
        if (count <= 0) {
            throw ExceptionUtils.mpe("%s", "号源数量更新失败!");
        }
        return true;
    }

    //校验
    public boolean checkFor(Patient patient, SchedulingDetailVo detailVo) {
        if (patient == null) {
            throw ExceptionUtils.mpeValidator("%s", "病人信息不存在!");
        }
        if (detailVo == null) {
            throw ExceptionUtils.mpeValidator("%s", "号源信息不存在!");
        }

        if ("1".equals(detailVo.getRegApe()) && !ApplicationConstants.Y.equals(detailVo.getScheAmState())) {
            throw ExceptionUtils.mpeValidator("%s", "排班状态已更新!");
        }
        if ("2".equals(detailVo.getRegApe()) && !ApplicationConstants.Y.equals(detailVo.getSchePmState())) {
            throw ExceptionUtils.mpeValidator("%s", "排班状态已更新!");
        }
        if ("3".equals(detailVo.getRegApe()) && !ApplicationConstants.Y.equals(detailVo.getScheEveState())) {
            throw ExceptionUtils.mpeValidator("%s", "排班状态已更新!");
        }

        Integer count = schedulingDetailReadMapper.getBreachAppointment(patient.getPtId().toString());
        if (count >= 3) {
            throw ExceptionUtils.mpeValidator("%s", "已爽约三次,无法继续操作!");
        }

        return true;
    }
    //获取预约记录
    public List<AppointRecordDto> getAppointRecord(Map<String, String> maps){
        Map<String,String> input = mapConvert(maps);
       List<AppointmentVo> appointmentVoList= schedulingDetailReadMapper.getAppointmentVoByMap(input);
       return AppointmentMapperImpl.INSTANCE.AppointmentVoListToAppointRecordDtoList(appointmentVoList);
    }

    private Map<String,String> mapConvert(Map<String,String> maps){
        String startDt = maps.get("startDt");//开始时间
        String endDt = maps.get("endDt");//结束时间
        if(Stringutils.isEmpty(startDt)){
            startDt = DateUtils.subDay(new Date(),-90,DateUtils.DATE_PATTERN);
        }
        if(Stringutils.isEmpty(endDt)){
            endDt = DateUtils.format(new Date(),DateUtils.DATE_PATTERN);
        }
        String ioNo = maps.get("ioNo");
        if(Stringutils.isEmpty(ioNo)){
            throw ExceptionUtils.mpeValidator("%s", "病人就诊号不能为空!");
        }
        Patient patient = patientReadMapper.getByIoNo(ioNo);
        if(patient==null){
            throw ExceptionUtils.mpeValidator("%s", "病人信息不存在!");
        }
        Map<String,String> input = new HashMap<>();
        input.put("startDt",startDt);
        input.put("endDt",endDt);
        input.put("ptId",patient.getPtId().toString());
        return input;
    }
    //获取挂号记录
    public  List<AppointRecordDto> getRegisterRecord(Map<String, String> maps){
        Map<String,String> input = mapConvert(maps);
        List<AppointmentVo> appointmentVoList= schedulingDetailReadMapper.getAppointmentVoByRegisterMap(input);
        return AppointmentMapperImpl.INSTANCE.AppointmentVoListToAppointRecordDtoList(appointmentVoList);
    }
//更新爽约
    public boolean updateBreakAppoint(){
        List<Appointment> appointmentList = schedulingDetailReadMapper.getBreakAppointmentList();
        if(CollectionUtils.isNotEmpty(appointmentList)){
            for (Appointment appointment: appointmentList){
                appointment.setAppointState("4");
                appointment.setAppointBlacklist(ApplicationConstants.Y);
                appointment.setAppointCancalOptCode("001");
                appointment.setAppointCancelDate(new Date());
                schedulingDetailOptMapper.updateBreakAppointment(appointment);
            }
        }
        return true;
    }
}
